package com.simple.datax.compress.impl;

import java.util.List;

import org.apache.xmlbeans.XmlObject;

import com.alibaba.dubbo.common.io.Bytes;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.simple.datax.SimpleMessage;
import com.simple.datax.api.CommonSimpleException;
import com.simple.datax.api.MessageProcessor;
import com.simple.datax.api.SimpleException;
import com.simple.datax.service.AbstractMessageProcessor;
import com.simple.datax.utils.MessageGZIP;
import com.simple.datax.utils.MessageZIP;
import com.simple.datax.utils.SimpleConstants;
import com.simple.datax.xml.ec.EC101MessageDocument;
import com.simple.datax.xml.ec.EC101MessageDocument.EC101Message;
import com.simple.datax.xml.ec.EC101ResponseDocument;
import com.simple.datax.xml.tcs.TCS101MessageDocument;
import com.simple.datax.xml.tcs.TCS101MessageDocument.TCS101Message;
import com.simple.datax.xml.tcs.TCS101ResponseDocument;

/**
 * @Title: MessageUnCompressImpl.java
 * @Package com.simple.datax.compress.impl
 * @Description: 报文解压，（因为报文解压是在parse之后，所以该处理应该先读smipleMessage的intraDoc对象）
 * 
 *               报文压缩要求，设置messageHead中的compress为true， 支持两种方式压缩：GZip，Zip；
 *               根据压缩方式，在messagebody中直接放入
 *               <GZip>compressData</GZip>或者<Zip>compressData</Zip>
 *               compressData为，GZip（Zip）之后的byte[]直接转成16进制字符串。
 * 
 *               对于需要解压缩的判断，目前按如下方式实现： 1、 必须收到的报文头中compress为true 2、
 *               发送至本Node的内部处理list中ID的
 *               ，都不处理；（这一项只用在Router中配置了，内部处理和其他企业采用同样的通讯方式时才能用到） 3、
 *               发送到本Node的其他ID都要处理率； 4、 发送到其他Node的都要处理；
 * 
 * @author Paladin Chen
 * @date 2013-1-10 下午1:46:24
 * @version V1.0
 */
public class MessageUnCompressImpl extends AbstractMessageProcessor implements MessageProcessor {
	private static final Logger logger = LoggerFactory.getLogger(MessageUnCompressImpl.class);
	private String localNode = "EC0001";

	private List<String> intraProcCode;

	@Override
	public void realProcess(SimpleMessage src) throws SimpleException {
		logger.debug("Begin to UnCompress....." + src.toLog());

		try {
			setErrorInfos(SimpleConstants.ERROR_TYPE_DATAXPROC, SimpleConstants.ERROR_LEVEL_NORMAL,
					SimpleConstants.RESPONSE_CODE_UNCOMPRESS, SimpleConstants.RESPONSE_MSG_UNCOMPRESS);
			// 如果上来的报文是压缩的，则解压
			if (checkNeedUncompress(src)) {
				uncompress(src);
			}

			callNextStep(src);
		} catch (Exception e) {
			throw new CommonSimpleException("UnCompress Error:" + e.getMessage(), e);
		}

		logger.debug("Finish UnCompress....." + src.toLog());
	}

	/**
	 * 检查是否需要解压缩
	 * 
	 * 因为平台内部过来的报文有可能，带有compress标记，但是都不应该是压缩报文，先预留
	 * 
	 * @param src
	 * @return
	 */
	private boolean checkNeedUncompress(SimpleMessage src) {
		if (src.isCompress()) {
			if (localNode.equalsIgnoreCase(src.getReceiverNode())) {
				String receiver = src.getReceiver().toUpperCase();

				if (intraProcCode.contains(receiver)) {
					return false;
				}
			}

			return true;
		}
		return false;
	}

	private void uncompress(SimpleMessage src) throws CommonSimpleException {
		if (src.getIntraDoc() != null) {
			XmlObject iDoc = src.getIntraDoc();
			try {
				if (iDoc instanceof EC101MessageDocument) {
					EC101Message ecmsg = ((EC101MessageDocument) iDoc).getEC101Message();
					XmlObject tcsBody = XmlObject.Factory.parse(ecmsg.getMessageBody().xmlText());

					String compressType = tcsBody.getDomNode().getFirstChild().getNodeName();
					String compressContent = tcsBody.xmlText();

					String unCompressContent = uncompress(compressContent, compressType);

					ecmsg.setMessageBody(com.simple.datax.xml.ec.XMLDATA.Factory.parse(unCompressContent));
					
					//解压之后设置压缩标志位false
					ecmsg.getMessageHead().setDataCompress("false");
				} else if (iDoc instanceof EC101ResponseDocument) {
					// 暂不支持
					logger.info("EC101ResponseDocument not support Compress Now!!");
					// EC101Response ecres = ((EC101ResponseDocument)
					// iDoc).getEC101Response();
					// String compressType =
					// ecres.getMessageBody().getDomNode().getFirstChild().getNodeName();
					// String compressContent =
					// ecres.getMessageBody().getDomNode().getFirstChild().getNodeValue();
					// String unCompressContent = uncompress(compressContent,
					// compressType);
					//
					// ecres.setMessageBody(EC101Response.MessageBody.Factory.parse(unCompressContent));
					//
					// com.simple.datax.xml.tcs.XMLDATA;
				} else if (iDoc instanceof TCS101MessageDocument) {
					TCS101Message tcsmsg = ((TCS101MessageDocument) iDoc).getTCS101Message();
					XmlObject tcsBody = XmlObject.Factory.parse(tcsmsg.getMessageBody().xmlText());

					String compressType = tcsBody.getDomNode().getFirstChild().getNodeName();
					String compressContent = tcsBody.xmlText();

					String unCompressContent = uncompress(compressContent, compressType);

					tcsmsg.setMessageBody(com.simple.datax.xml.tcs.XMLDATA.Factory.parse(unCompressContent));
					
					//解压之后设置压缩标志位false
					tcsmsg.getMessageHead().setDataCompress("false");
				} else if (iDoc instanceof TCS101ResponseDocument) {
					logger.info("TCS101ResponseDocument not support Compress Now!!");
				} else {
					// 不做处理
					logger.info("Unkown Document not support Compress Now!!");
				}
			} catch (Exception e) {
				throw new CommonSimpleException(e.getMessage(), e);
			}
		}
	}

	private String uncompress(String content, String compressType) throws Exception {
		if (content == null) {
			return null;
		}

		content = catHeadandTail(content);
		if ("gzip".equalsIgnoreCase(compressType)) {
			return MessageGZIP.uncompressToString(Bytes.hex2bytes(content));
		} else if ("zip".equalsIgnoreCase(compressType)) {
			return MessageZIP.uncompressToString(Bytes.hex2bytes(content));
		} else {
			return content;
		}
	}

	private String catHeadandTail(String content) {
		if (content != null) {
			if (content.contains(">")) {
				content = content.substring(content.indexOf(">") + 1);
			}

			if (content.contains("<")) {
				content = content.substring(0, content.indexOf("<"));
			}
		}

		return content;
	}

	public void uncompresst(SimpleMessage src) {
		try {
			uncompress(src);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public String getLocalNode() {
		return localNode;
	}

	public void setLocalNode(String localNode) {
		this.localNode = localNode;
	}

	public List<String> getIntraProcCode() {
		return intraProcCode;
	}

	public void setIntraProcCode(List<String> intraProcCode) {
		this.intraProcCode = intraProcCode;
	}

}
